import { Page } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';

/**
 * 证据收集器 - 收集测试过程中的各种证据
 * 包括录屏、HAR文件、截图、日志等
 */
export class EvidenceCollector {
  private testTimestamp: string;
  private evidenceDir: string;
  private isRecording: boolean = false;

  constructor(testTimestamp: string) {
    this.testTimestamp = testTimestamp;
    this.evidenceDir = path.join(process.cwd(), 'test-results', 'evidence', testTimestamp);
    this.ensureEvidenceDir();
  }

  private ensureEvidenceDir(): void {
    if (!fs.existsSync(this.evidenceDir)) {
      fs.mkdirSync(this.evidenceDir, { recursive: true });
    }
  }

  /**
   * 开始录屏
   */
  async startRecording(page: Page): Promise<void> {
    try {
      const videoPath = path.join(this.evidenceDir, 'test-recording.webm');
      
      // Playwright会自动处理录屏，我们只需要确保配置正确
      // 录屏文件会在测试结束后自动保存到test-results目录
      this.isRecording = true;
      
      console.log(`开始录屏，将保存到: ${videoPath}`);
    } catch (error) {
      console.warn('录屏启动失败:', error);
    }
  }

  /**
   * 停止录屏
   */
  async stopRecording(): Promise<void> {
    if (this.isRecording) {
      this.isRecording = false;
      console.log('录屏已停止');
    }
  }

  /**
   * 保存截图
   */
  async saveScreenshot(name: string, screenshot: Buffer): Promise<void> {
    const filename = `${name}-${this.testTimestamp}.png`;
    const filepath = path.join(this.evidenceDir, filename);
    
    fs.writeFileSync(filepath, screenshot);
    console.log(`截图已保存: ${filepath}`);
  }

  /**
   * 保存HAR文件（HTTP Archive）
   */
  async saveHAR(page: Page): Promise<void> {
    try {
      const harPath = path.join(this.evidenceDir, `network-${this.testTimestamp}.har`);
      
      // 获取网络请求记录
      const context = page.context();
      
      // 注意：需要在测试开始前启用HAR记录
      // 这里我们创建一个简化的网络日志
      const networkLog = {
        timestamp: new Date().toISOString(),
        testId: this.testTimestamp,
        note: 'HAR recording requires context setup at test start',
        requests: []
      };
      
      fs.writeFileSync(harPath, JSON.stringify(networkLog, null, 2));
      console.log(`HAR文件已保存: ${harPath}`);
    } catch (error) {
      console.warn('HAR文件保存失败:', error);
    }
  }

  /**
   * 保存数据到JSON文件
   */
  async saveData(name: string, data: any): Promise<void> {
    const filename = `${name}-${this.testTimestamp}.json`;
    const filepath = path.join(this.evidenceDir, filename);
    
    const dataWithMeta = {
      timestamp: new Date().toISOString(),
      testId: this.testTimestamp,
      data: data
    };
    
    fs.writeFileSync(filepath, JSON.stringify(dataWithMeta, null, 2));
    console.log(`数据已保存: ${filepath}`);
  }

  /**
   * 保存文件副本
   */
  async saveFile(name: string, sourcePath: string): Promise<void> {
    const filename = `${name}-${this.testTimestamp}${path.extname(sourcePath)}`;
    const filepath = path.join(this.evidenceDir, filename);
    
    fs.copyFileSync(sourcePath, filepath);
    console.log(`文件已保存: ${filepath}`);
  }

  /**
   * 保存错误报告
   */
  async saveErrorReport(errors: string[], attempt: number): Promise<void> {
    const errorReport = {
      timestamp: new Date().toISOString(),
      testId: this.testTimestamp,
      attempt: attempt,
      errors: errors,
      errorCount: errors.length,
      summary: this.generateErrorSummary(errors)
    };
    
    const filename = `error-report-attempt-${attempt}-${this.testTimestamp}.json`;
    const filepath = path.join(this.evidenceDir, filename);
    
    fs.writeFileSync(filepath, JSON.stringify(errorReport, null, 2));
    console.log(`错误报告已保存: ${filepath}`);
  }

  /**
   * 生成错误摘要
   */
  private generateErrorSummary(errors: string[]): any {
    const summary = {
      totalErrors: errors.length,
      errorTypes: {
        missingColumns: 0,
        typeErrors: 0,
        enumErrors: 0,
        validationErrors: 0,
        other: 0
      },
      suggestions: [] as string[]
    };

    for (const error of errors) {
      const errorLower = error.toLowerCase();
      
      if (errorLower.includes('缺少') || errorLower.includes('missing')) {
        summary.errorTypes.missingColumns++;
        summary.suggestions.push('添加缺失的列');
      } else if (errorLower.includes('类型') || errorLower.includes('type')) {
        summary.errorTypes.typeErrors++;
        summary.suggestions.push('检查数据类型');
      } else if (errorLower.includes('枚举') || errorLower.includes('enum')) {
        summary.errorTypes.enumErrors++;
        summary.suggestions.push('使用正确的枚举值');
      } else if (errorLower.includes('验证') || errorLower.includes('validation')) {
        summary.errorTypes.validationErrors++;
        summary.suggestions.push('检查数据验证规则');
      } else {
        summary.errorTypes.other++;
      }
    }

    // 去重建议
    summary.suggestions = [...new Set(summary.suggestions)];
    
    return summary;
  }

  /**
   * 保存后端日志摘要
   */
  async saveBackendLogs(jobId: string, logs: any[]): Promise<void> {
    const logSummary = {
      timestamp: new Date().toISOString(),
      testId: this.testTimestamp,
      jobId: jobId,
      logs: logs,
      summary: {
        totalLogs: logs.length,
        errorCount: logs.filter(log => log.level === 'error').length,
        warningCount: logs.filter(log => log.level === 'warning').length,
        infoCount: logs.filter(log => log.level === 'info').length
      }
    };
    
    const filename = `backend-logs-${jobId}-${this.testTimestamp}.json`;
    const filepath = path.join(this.evidenceDir, filename);
    
    fs.writeFileSync(filepath, JSON.stringify(logSummary, null, 2));
    console.log(`后端日志已保存: ${filepath}`);
  }

  /**
   * 保存数据库快照
   */
  async saveDatabaseSnapshot(name: string, snapshot: any): Promise<void> {
    const snapshotData = {
      timestamp: new Date().toISOString(),
      testId: this.testTimestamp,
      snapshotName: name,
      data: snapshot,
      recordCount: Array.isArray(snapshot) ? snapshot.length : 
                   (snapshot && typeof snapshot === 'object' && snapshot.count) ? snapshot.count : 'unknown'
    };
    
    const filename = `db-snapshot-${name}-${this.testTimestamp}.json`;
    const filepath = path.join(this.evidenceDir, filename);
    
    fs.writeFileSync(filepath, JSON.stringify(snapshotData, null, 2));
    console.log(`数据库快照已保存: ${filepath}`);
  }

  /**
   * 生成证据包摘要
   */
  async generateEvidencePackage(): Promise<string> {
    const files = fs.readdirSync(this.evidenceDir);
    
    const evidencePackage = {
      timestamp: new Date().toISOString(),
      testId: this.testTimestamp,
      evidenceDir: this.evidenceDir,
      files: files.map(file => ({
        name: file,
        size: fs.statSync(path.join(this.evidenceDir, file)).size,
        created: fs.statSync(path.join(this.evidenceDir, file)).ctime
      })),
      summary: {
        totalFiles: files.length,
        screenshots: files.filter(f => f.endsWith('.png')).length,
        dataFiles: files.filter(f => f.endsWith('.json')).length,
        excelFiles: files.filter(f => f.endsWith('.xlsx')).length,
        videos: files.filter(f => f.endsWith('.webm')).length,
        harFiles: files.filter(f => f.endsWith('.har')).length
      }
    };
    
    const packagePath = path.join(this.evidenceDir, `evidence-package-${this.testTimestamp}.json`);
    fs.writeFileSync(packagePath, JSON.stringify(evidencePackage, null, 2));
    
    console.log(`证据包摘要已生成: ${packagePath}`);
    return packagePath;
  }

  /**
   * 获取证据目录路径
   */
  getEvidenceDir(): string {
    return this.evidenceDir;
  }

  /**
   * 清理旧的证据文件
   */
  async cleanupOldEvidence(daysOld: number = 7): Promise<void> {
    const evidenceBaseDir = path.join(process.cwd(), 'test-results', 'evidence');
    
    if (!fs.existsSync(evidenceBaseDir)) {
      return;
    }
    
    const cutoffTime = Date.now() - (daysOld * 24 * 60 * 60 * 1000);
    const dirs = fs.readdirSync(evidenceBaseDir);
    
    for (const dir of dirs) {
      const dirPath = path.join(evidenceBaseDir, dir);
      const stat = fs.statSync(dirPath);
      
      if (stat.isDirectory() && stat.ctime.getTime() < cutoffTime) {
        fs.rmSync(dirPath, { recursive: true, force: true });
        console.log(`已清理旧证据目录: ${dirPath}`);
      }
    }
  }
}